<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */
namespace app\service\cdc;

use app\enum\CdcEnum;
use app\model\mongo\MongoAppendSyncModel;
use app\model\mongo\MongoInfoModel;
use app\model\mongo\MongoReportModel;
use app\model\mongo\MongoSyncModel;
use app\service\BaseService;

/**
 * 账户变更服务
 */
class AccountChangeService extends BaseService
{
    /**
     * @var int 旧账户id
     */
    private int $oldAccountId = 0;

    /**
     * @var int 旧客户id
     */
    private int $oldClientId = 0;

    /**
     * @var int 新账户id
     */
    private int $newAccountId = 0;

    /**
     * @var int 新客户id
     */
    private int $newClientId = 0;

    /**
     * @var string 旧账户名称
     */
    private string $advId = '';

    /**
     * @var int 媒体id
     */
    private int $mediaId = 0;

    public function __construct()
    {
    }

    /**
     * 账户切换修复.
     *
     * @param string $str 账户信息
     */
    public function startChange(string $str = ''): bool
    {
        if (! $str) {
            return self::setError('未知账户信息');
        }
        $arr = explode('_', $str);
        $this->oldAccountId = intval($arr[0] ?? 0);
        $this->oldClientId = intval($arr[1] ?? 0);
        $this->newAccountId = intval($arr[2] ?? 0);
        $this->newClientId = intval($arr[3] ?? 0);
        $this->advId = strval($arr[4] ?? '');
        $this->mediaId = intval($arr[5] ?? 0);
        if ($this->oldAccountId <= 0 || $this->oldClientId <= 0 || $this->newAccountId <= 0 || $this->newClientId <= 0 || $this->advId == '' || ! $this->mediaId) {
            return self::setError('参数错误');
        }

        return $this->runChange();
    }

    /**
     * 账户变更切换.
     */
    private function runChange(): bool
    {
        // 修复基础信息
        foreach (CdcEnum::getClassNames($this->mediaId, 'info') as $classname) {
            if (! $this->changeInfo($classname)) {
                return false;
            }
        }

        // 修复报表信息
        foreach (CdcEnum::getClassNames($this->mediaId, 'report') as $classname) {
            if (! $this->changeReport($classname)) {
                return false;
            }
        }

        // 修复同步信息
        foreach (CdcEnum::getClassNames($this->mediaId, 'sync') as $classname) {
            if (! $this->changeSync($classname)) {
                return false;
            }
        }

        // 修复追加信息
        foreach (CdcEnum::getClassNames($this->mediaId, 'sync_append') as $classname) {
            if (! $this->changeAppendSync($classname)) {
                return false;
            }
        }

        // 开启报表同步
        foreach (CdcEnum::getClassNames($this->mediaId, 'report') as $classname) {
            if (! $this->restartReport($classname)) {
                return false;
            }
        }

        return true;
    }

    /**
     * 更新基础信息关系.
     *
     * @param string $classname 类名称
     */
    private function changeInfo(string $classname = ''): bool
    {
        $items = (new $classname())->where(['adv_id' => $this->advId])->order('account_id', 'desc')->select();
        if (! $items) {
            return true;
        }
        foreach ($items as $model) {
            if (! $model instanceof MongoInfoModel || ! $model->getKey()) {
                return self::setError('获取关系对象失败');
            }

            if ($model->getAttr('account_id') == $this->newAccountId) {
                // 新数据更新
                $fields = $model->getRepairField();

                $where = [];
                foreach ($fields as $v) {
                    $where[$v] = $model->getAttr($v);
                }
                $where['account_id'] = $this->oldAccountId;

                (new $classname())->where($where)->delete();
                $model->setAttrs([
                    'client_id' => $this->newClientId,
                    'account_id' => $this->newAccountId,
                ]);
                $model->save();
            } else {
                // 老数据更新
                $oldModel = (new $classname())->where(['_id' => $model->getKey()])->find();

                if ($oldModel instanceof MongoInfoModel && $oldModel->getKey()) {
                    $oldModel->setAttrs([
                        'client_id' => $this->newClientId,
                        'account_id' => $this->newAccountId,
                    ]);
                    $oldModel->save();
                }
            }
        }
        return true;
    }

    /**
     * 更新日报信息关系.
     *
     * @param string $classname 类名称
     */
    private function changeReport(string $classname = ''): bool
    {
        $obj = new $classname();
        if (! $obj instanceof MongoReportModel) {
            return self::setError('获取报表模型失败');
        }

        $obj->where(['account_id' => $this->oldAccountId])->update([
            'client_id' => $this->newClientId,
            'account_id' => $this->newAccountId,
            'is_sync' => $obj::SYNC_YES,
        ]);

        return true;
    }

    /**
     * 更新同步信息关系.
     *
     * @param string $classname 类名称
     */
    private function changeSync(string $classname = ''): bool
    {
        $obj = new $classname();
        if (! $obj instanceof MongoSyncModel) {
            return self::setError('获取同步模型失败');
        }
        (new $classname())->where(['adv_id' => $this->advId])->delete();

        return true;
    }

    /**
     * 更新追加信息关系.
     *
     * @param string $classname 类名称
     */
    private function changeAppendSync(string $classname = ''): bool
    {
        $obj = new $classname();
        if (! $obj instanceof MongoAppendSyncModel) {
            return self::setError('获取追加模型失败');
        }
        (new $classname())->where(['adv_id' => $this->advId])->delete();

        return true;
    }

    /**
     * 重启日报信息关系.
     *
     * @param string $classname 类名称
     */
    private function restartReport(string $classname = ''): bool
    {
        $obj = new $classname();
        if (! $obj instanceof MongoReportModel) {
            return self::setError('获取报表模型失败');
        }
        $obj->where(['adv_id' => $this->advId])->update([
            'is_sync' => $obj::SYNC_NO,
        ]);

        return true;
    }
}
